package com.sciencep.pro.admin.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.request.OapiSnsGetuserinfoBycodeRequest;
import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
import com.sciencep.pro.admin.system.common.authentication.JWTToken;
import com.sciencep.pro.admin.system.common.authentication.JWTUtil;
import com.sciencep.pro.admin.system.service.LoginService;
import com.sciencep.pro.common.config.Constant;
import com.sciencep.pro.common.domain.ResponseResult;
import com.sciencep.pro.common.exception.CustomException;
import com.sciencep.pro.common.utils.DateUtil;
import com.sciencep.pro.core.dao.UserMapper;
import com.sciencep.pro.core.domain.dto.account.AccountDetail;
import com.sciencep.pro.core.domain.dto.user.UserDetail;
import com.sciencep.pro.core.domain.entity.Account;
import com.sciencep.pro.core.domain.entity.User;
import com.sciencep.pro.core.service.IAccountService;
import com.sciencep.pro.core.service.IUserService;
import com.sciencep.pro.core.service.RedisService;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.sciencep.pro.common.config.Constant.USERINFO_CACHE_PREFIX;

@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Value("${pro.shiro.jwtTimeOut}")
    private Long jwtTimeOut;

    @Autowired
    IUserService userService;

    @Autowired
    RedisService redisService;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private JWTUtil jwtUtil;

    @Autowired
    private IAccountService accountService;

    @Value("${secretKey.appId}")
    String systemAppId;

    @Value("${secretKey.appSecret}")
    String systemSecret;

    @Override
    public UserDetail login(String userId) throws CustomException {

        if (StringUtils.isEmpty(userId)) {
            throw new CustomException("用户ID不能为空");
        }
        userId = userId.toLowerCase();
        UserDetail userDetail = userService.getUserDetailByUserId(userId);
        if (userDetail == null) {
            throw new CustomException("用户不存在");
        }
        String token = jwtUtil.sign(userId);
        LocalDateTime expireTime = LocalDateTime.now().plusSeconds(jwtTimeOut);
        String expireTimeStr = DateUtil.formatFullTime(expireTime);
        JWTToken jwtToken = new JWTToken(token, expireTimeStr);


        userDetail.setToken(jwtToken.getToken());
        userDetail.setExpireTimeStr(expireTimeStr);
        String key = USERINFO_CACHE_PREFIX + userId;
        try {
            redisService.set(key, JSON.toJSONString(userDetail));
        } catch (Exception e) {
            log.error("redis出错： {}", e.getMessage());
            throw new CustomException("系统繁忙");
        }

        return userDetail;
    }

    @Override
    public ResponseResult<Object> getUserByCode(String code) throws ApiException, CustomException {
        String errorMessage = "登录信息有误,请联系管理员";
        DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/sns/getuserinfo_bycode");
        OapiSnsGetuserinfoBycodeRequest req = new OapiSnsGetuserinfoBycodeRequest();
        req.setTmpAuthCode(code);
        // 70服务器
        String appId = systemAppId;
        String appSecret = systemSecret;
        OapiSnsGetuserinfoBycodeResponse response = client.execute(req, appId, appSecret);

        if (response.getErrcode() != 0) {
            return new ResponseResult<>().failure(response.getErrorCode(), "扫码登录失败");
        }

        String unionId = response.getUserInfo().getUnionid();
        if (unionId == null || unionId.length() == 0) {
            return new ResponseResult<>().failure("356", errorMessage);
        }

        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUnionId, unionId).select(User::getUserId));
        if (null == user || null == user.getUserId()) {
            return new ResponseResult<>().failure("356", errorMessage);
        }
        UserDetail userDetail = this.login(user.getUserId());

        return new ResponseResult<>().success(userDetail);
    }

    @Override
    public ResponseResult<Object> getAccount(Account account) throws CustomException {
        String errorMessage = "登录信息有误,请联系管理员";

        Account accountInfo = accountService.getOne(new LambdaQueryWrapper<Account>().eq(Account::getAccountNumber,account.getAccountNumber()).eq(Account::getPassWord,account.getPassWord()).eq(Account::getIsDel,Constant.IsDelete.NO));
        if (null == accountInfo) {
            return new ResponseResult<>().failure("356", errorMessage);
        }

        AccountDetail accountDetail = new AccountDetail();
        accountDetail.setAccountNumber(accountInfo.getAccountNumber());
        accountDetail.setPassWord(account.getPassWord());
        //直接赋值日志管理-人天审查的权限
        List<String> buttonStr = new ArrayList<>();
        buttonStr.add("log.logEdit.list");
        accountDetail.setButtonIds(buttonStr);

        String token = jwtUtil.sign(accountDetail.getAccountNumber());
        LocalDateTime expireTime = LocalDateTime.now().plusSeconds(jwtTimeOut);
        String expireTimeStr = DateUtil.formatFullTime(expireTime);
        JWTToken jwtToken = new JWTToken(token, expireTimeStr);


        accountDetail.setToken(jwtToken.getToken());
        accountDetail.setExpireTimeStr(expireTimeStr);
        String key = USERINFO_CACHE_PREFIX + accountDetail.getAccountNumber();
        try {
            redisService.set(key, JSON.toJSONString(accountDetail));
        } catch (Exception e) {
            log.error("redis出错： {}", e.getMessage());
            throw new CustomException("系统繁忙");
        }

        return new ResponseResult<>().success(accountDetail);
    }

    @Override
    public ResponseResult<Object> getUserByCode1(String code) throws ApiException, CustomException {
        String errorMessage = "登录信息有误,请联系管理员";
        DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/sns/getuserinfo_bycode");
        OapiSnsGetuserinfoBycodeRequest req = new OapiSnsGetuserinfoBycodeRequest();
        req.setTmpAuthCode(code);
        // 公司服务器  appId
        String appId = "dingoalmomqwefd7wv0vgh";
        String appSecret = "GmLHYvCwHp5icEoAGj8ZLieRyeaA2FbC7G6KvX_RS3zxTK6OlFbunuTN45WZN5si";
        OapiSnsGetuserinfoBycodeResponse response = client.execute(req, appId, appSecret);

        if (response.getErrcode() != 0) {
            return new ResponseResult<>().failure(response.getErrorCode(), "扫码登录失败");
        }

        String unionId = response.getUserInfo().getUnionid();
        if (unionId == null || unionId.length() == 0) {
            return new ResponseResult<>().failure("356", errorMessage);
        }

        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUnionId, unionId).select(User::getUserId));
        if (null == user || null == user.getUserId()) {
            return new ResponseResult<>().failure("356", errorMessage);
        }
        UserDetail userDetail = this.login(user.getUserId());

        return new ResponseResult<>().success(userDetail);
    }
}
